/**
 * 
 */
package info.niwota.ispy;

import java.util.Calendar;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;

/**
 * @author qiangli
 * 
 */
public class MonitorService extends Service {

	private static final String TAG = "MonitorService";

	private static final String CIQ_STARTED = "com.carrieriq.iqagent.SERVICE_STARTED";

	private static final String SPRINT_EXT_STARTED = "com.sprint.android.SPRINTEXTENSION_STARTED";

	public class LocalBinder extends Binder {
		MonitorService getService() {
			return MonitorService.this;
		}
	}

	private final IBinder binder = new LocalBinder();

	@Override
	public IBinder onBind(Intent i) {
		return binder;
	}

	private int monitorInterval = 0; //no check be default
	
	private final BroadcastReceiver timeReceiver = new BroadcastReceiver() {
		private int tickCount = 0;

		@Override
		public void onReceive(Context ctx, Intent intent) {
			if (Debug.DEBUG) {
				Log.d(TAG, "timeReceiver " + " context: " + ctx + " intent: "
						+ intent + " interval: " + monitorInterval );
			}
			
			if (monitorInterval == 0) {
				tickCount = 0;
				
				return;
			}
			
			final String action = intent.getAction();
			//
			Calendar c = Calendar.getInstance();
			c.setTimeInMillis(System.currentTimeMillis());
			
			if (action.equals(Intent.ACTION_TIME_TICK)) {
				tickCount++;
				//
				if (Debug.DEBUG) {
					Log.d(TAG, "onReceive ACTION_TIME_TICK tickCount: " + tickCount);
				}
				if (tickCount >= monitorInterval) {
					tickCount = 0;
					
					checkLogs();
				}
			}
		}
	};

	private final BroadcastReceiver receiver = new BroadcastReceiver() {

		public void onReceive(Context ctx, Intent intent) {
			final String action = intent.getAction();

			if (Debug.DEBUG) {
				Log.d(TAG, "receiver action: " + action);
			}
			
			StringBuilder sb = new StringBuilder();
			ComponentName cn = intent.getComponent();
			if (cn != null) {
				sb.append(cn.toString());
			} else {
				sb.append(action);
			}
			String desc = ctx.getString(R.string.msg_ciq_started, sb.toString());
			
			if (SPRINT_EXT_STARTED.equals(action) || CIQ_STARTED.equals(action)) {
				Notifications.notify(ctx, desc);
			}
		}
	};

	private Handler handler = new Handler();
	private ContentObserver observer = null;
	private boolean ciqEnabled = false;

	private class SettingsContentObserver extends ContentObserver {

		public SettingsContentObserver(Handler handler) {
			super(handler);
		}

		@Override
		public boolean deliverSelfNotifications() {
			return false;
		}

		@Override
		public void onChange(boolean selfChange) {
			final Context ctx = MonitorService.this;
			final boolean b = Utils.isCIQLoggingEnabled(ctx);
			
			//check cig logging setting
			if (b != ciqEnabled) {
				alertSetting(b);
			}
			ciqEnabled = b;
		}
	}
	
	private long logTotal = 0;
	private long logCount = 0;
	private String logEntry = null; //last entry
	private Thread logThread = null;
	
	private IQEntryCallback callback = new IQEntryCallback() {
		public void found(long total, String line) {
			logTotal = total;
			logEntry = line;
			logCount++;
		}
	};

	@Override
	public void onCreate() {
		super.onCreate();

		if (Debug.DEBUG) {
			Log.d(TAG, "onCreate");
		}

		try {
			//alert if enabled 
			ciqEnabled = Utils.isCIQLoggingEnabled(this);
			if (ciqEnabled) {
				alertSetting(true);
			}
	
			//
			IntentFilter timefilter = new IntentFilter();
			timefilter.addAction(Intent.ACTION_TIME_TICK);
			timefilter.addAction(Intent.ACTION_TIME_CHANGED);
			timefilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
			registerReceiver(timeReceiver, timefilter);
			
			//
			IntentFilter intentFilter = null;
			intentFilter = new IntentFilter();
			intentFilter.addAction(CIQ_STARTED);
			intentFilter.addAction(SPRINT_EXT_STARTED);
			registerReceiver(receiver, intentFilter);
			
			//
			observer = new SettingsContentObserver(handler);
			ContentResolver cr = getContentResolver();
			cr.registerContentObserver(Settings.System.CONTENT_URI, true, observer);
			cr.registerContentObserver(Settings.Secure.CONTENT_URI, true, observer);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	synchronized private void checkLogs() {
		//alert if new entry since last check

		if (Debug.DEBUG) {
			Log.d(TAG, "checkLogs total: " + logTotal + " count: " + logCount + " entry: " + logEntry);
		}
		
		if (logCount > 0) {
			final Context ctx = this;
			final String desc = ctx.getString(R.string.msg_log_ciq_found, logTotal, logEntry);
			Notifications.notify(ctx, desc);
		}
		
		logCount = 0;
	}

	private void alertSetting(boolean b) {
		final Context ctx = this;
		final String desc = ctx.getString(R.string.msg_setting_changed, Boolean.toString(b));
		Notifications.notify(ctx, desc);
	}

	@Override
	public void onDestroy() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onDestroy");
		}

		try {
			if (timeReceiver != null) {
				unregisterReceiver(timeReceiver);
			}
			
			//
			if (receiver != null) {
				unregisterReceiver(receiver);
			}

			//
			if (observer != null) {
				ContentResolver cr = getContentResolver();
				cr.unregisterContentObserver(observer);
			}
			observer = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//
		resetLogcat();
		
		//
		super.onDestroy();
	}

	@Override
	public void onStart(Intent intent, int startId) {
		handleCommand(intent);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		handleCommand(intent);
		return START_STICKY;
	}

	private void handleCommand(Intent intent) {
		final Context ctx = this;
		
		monitorInterval = Preferences.getMonitorInterval(ctx);

		if (Debug.DEBUG) {
			Log.d(TAG, "handleCommand intent: " + intent + " interval: " + monitorInterval);
		}
		
		resetLogcat(); 
		
		boolean enableMonitoring = (monitorInterval > 0);
		if (enableMonitoring) {
			logThread = Logcat.tail(callback);
		}
	}

	private void resetLogcat() {
		if (Debug.DEBUG) {
			Log.d(TAG, "resetLogcat");
		}
		
		//
		if (logThread != null) {
			logThread.interrupt();
		}
		logThread = null;
		
		//
		logCount = 0;
		logTotal = 0;
		logEntry = null;
	}

	public static void shutdown(Context ctx) {
		Intent intent = new Intent(ctx, MonitorService.class);
		try {
			ctx.stopService(intent);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void startup(Context ctx) {
		Intent intent = new Intent(ctx, MonitorService.class);
		try {
			ctx.startService(intent);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void reload(Context ctx) {
		Intent intent = new Intent(ctx, MonitorService.class);
		try {
			ctx.startService(intent);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
